#define F_CPU 12000000UL
#define CODE_SIZE 6576

#include "vs.h"
#include "main.h"
#include <avr/io.h>
#ifndef ALIBC_OLD
#include <util/delay.h>
#else
#include <avr/delay.h>
#endif
//#include "vs_flac_patch.c"

extern const unsigned char atab[6576];
extern const unsigned short dtab[6576];


/* ========================== write/read/reset ===============================*/
void VS1053_SoftReset( void )
{
  VS_xCS_ENABLE();
  
  VS1053_spi_write( VS1053_WRITE );
  VS1053_spi_write( VS1053_SCI_MODE );
  VS1053_spi_write( SM_RESET>>8 ); /*MSB*/
  VS1053_spi_write( SM_RESET ); /*LSB*/
  
  VS_xCS_DISABLE();
  
  return;
}

void VS1053_Write( byte addr, UINT16 data )
{
  VS_xCS_ENABLE();

  VS1053_spi_write( VS1053_WRITE );
  VS1053_spi_write( addr );
  VS1053_spi_write( data>>8 ); /*MSB*/
  VS1053_spi_write( data ); /*LSB*/
  
  VS_xCS_DISABLE();
  
  return;
}

UINT16 VS1053_Read( byte addr )
{
  UINT16 data;
  data = 0x00;
  VS_xCS_ENABLE();
  
  VS1053_spi_write( VS1053_READ );
  data = VS1053_spi_read();
  data = data<<8 | VS1053_spi_read();
  
  VS_xCS_DISABLE();
  
  return data;
}

/*=============================== init/patch =============================================*/
void VS1053_Init( void )
{
  VS_xCS_DISABLE();
  VS_xDCS_DISABLE();
  
  SPSR &= ~(1<<SPI2X);
  
  VS_RST_ENABLE();
  _delay_ms(2);
  VS_RST_DISABLE();
  while( VS_DREQ_CHECK() ){};
  
  /* ------------- update SCI_MODE register */
  VS1053_Write( VS1053_SCI_MODE, 
		(~SM_DIFF|~SM_LAYER12|~SM_RESET|~SM_CANCEL|~SM_EARSPEAKER_LO|~SM_TESTS|~SM_STREAM|~SM_EARSPEAKER_HI|~SM_DACT|~SM_SDIORD|~SM_SDISHARE|SM_SDINEW|~SM_ADPCM|SM_LINE1|~SM_CLK_RANGE));
  while( VS_DREQ_CHECK() ){}; /* execution */
    
  /* ------------- update SCI_BASS register */
  VS1053_Write( VS1053_SCI_BASS, 0x0000 ); /* disable bass and treble boost*/
  while( VS_DREQ_CHECK() ){}; /* execution */
  
  /* ------------- update SCI_CLOCKF register */
  VS1053_Write( VS1053_SCI_CLOCKF, 0x8800 ); /* multiplier x3.5, add x1.0*/
  while( VS_DREQ_CHECK() ){}; /* execution */
    
  /* ------------- update SCI_VOL register */
  VS1053_Write( VS1053_SCI_VOL, 0x0606 ); /* volume for both channels -3.0dB*/
  while( VS_DREQ_CHECK() ){}; /* execution */
    
  SPSR |= (1<<SPI2X);
  
  VS1053_Patch();
    
  return;
}

void VS1053_Patch(void)
{
  UINT16 i;
  
  for( i=0x0000; i < CODE_SIZE; i++ )
  {
    VS1053_Write( atab[i], dtab[i] );
  }
  
  return;
}


/* =========================================== data send ======================================*/
void VS1053_Data32( byte* data )
{
  byte d, i;
  d = *data++;
  
  VS_xDCS_ENABLE();
  
  for( i=0x00; i < 0x20; i++ )
  {
    SPDR = d; d = *data++; loop_until_bit_is_set( SPSR, SPIF );
  }
  
  VS_xDCS_DISABLE();
  
  return;
}

void VS1053_Data( byte data )
{
  VS_xDCS_ENABLE();
  
  SPDR = data;
  loop_until_bit_is_set( SPSR, SPIF );
  
  VS_xDCS_DISABLE();
  
  return;
}

/*==================================================== volume/treble/bass control =================*/
void VS1053_SetVolume( byte vol )
{
  VS1053_Write( VS1053_SCI_VOL, (vol<<8 | vol ) );
  
  return;
}

byte VS1053_GetVolume( void )
{
  return VS1053_Read( VS1053_SCI_VOL );
}

void VS1053_SetBass( byte bass )
{
  UINT16 tmp;
  tmp = VS1053_Read( VS1053_SCI_BASS );
  tmp = tmp & 0xFF00;
  VS1053_Write( VS1053_SCI_BASS, ( tmp | bass ));
  
  return;
}

byte VS1053_GetBass( void )
{
  return VS1053_Read( VS1053_SCI_BASS );
}

void VS1053_SetTreble( byte treble )
{
  UINT16 tmp;
  tmp = VS1053_Read( VS1053_SCI_BASS );
  tmp = tmp & 0x00FF;
  VS1053_Write( VS1053_SCI_BASS, ( tmp | treble<<8 ));
  
  return;
}

byte VS1053_GetTreble( void )
{
  return (VS1053_Read( VS1053_SCI_BASS )>>8);
}

/*====================================================== spi related ==============================*/

void VS1053_spi_write( byte data )
{
  SPDR = data;
  loop_until_bit_is_set( SPSR, SPIF );
  
  return;
}

byte VS1053_spi_read( void )
{
  SPDR = 0xFF;
  loop_until_bit_is_set( SPSR, SPIF );
  
  return SPDR;
}